package com.rams.jhms.fs;

import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;

import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.exceptions.CannotReadException;
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
import org.jaudiotagger.audio.mp3.MP3File;
import org.jaudiotagger.tag.FieldKey;
import org.jaudiotagger.tag.Tag;
import org.jaudiotagger.tag.TagException;
import org.jaudiotagger.tag.id3.ID3v1Tag;
import org.jaudiotagger.tag.id3.ID3v24Frames;
import org.jaudiotagger.tag.id3.ID3v24Tag;

import com.rams.jhms.errors.FSException;
import com.rams.jhms.logging.BaseLogger;

public class FSFile {
	private File file;
	private AudioFile audioFile;
	private Tag tag;
	private MP3File mp3file;
	private ID3v1Tag mp3v1Tag;
	private ID3v24Tag mp3v2Tag;
	
	public FSFile(File file) {
		this.file = file;
	}
	
	public String getName() {
		return file.getName();
	}

	public String getArtist() {
		if (audioFile == null) {
			createAudioFile();
		}
		return tag.getFirst(FieldKey.ARTIST);
	}

	public String getTitle() {
		if (audioFile == null) {
			createAudioFile();
		}
		return tag.getFirst(FieldKey.TITLE);
	}

	public String getAlbum() {
		if (audioFile == null) {
			createAudioFile();
		}
		return tag.getFirst(FieldKey.ALBUM);
	}

	public String getGanre() {
		if (audioFile == null) {
			createAudioFile();
		}
		return tag.getFirst(FieldKey.GENRE);
	}

	public String getYear() {
		if (audioFile == null) {
			createAudioFile();
		}
		return tag.getFirst(FieldKey.YEAR);
	}

	/**
	 * Return file size in bytes
	 * @return file size in bytes
	 */
	public long getSize() {
		return file.length();
	}
	
	/**
	 * Return file size as formated string like 10b 10kB 10Mb
	 * @return file size
	 */
	public String getFormatedSize() {
		if (audioFile == null) {
			createAudioFile();
		}
		return byteFormater(getSize());
	}

	/**
	 * Return track duration in seconds
	 * @return track duration
	 */
	public int getTrackLength() {
		if (audioFile == null) {
			createAudioFile();
		}
		return audioFile.getAudioHeader().getTrackLength();
	}
	
	/**
	 * Return track duration as string like mmm:ss
	 * @return track duration string
	 */
	public String getFormatedTrackLength() {
		return timeFormater(getTrackLength());
	}

	/**
	 * Return track Quality as String like 44100 Hz, 128 kbps
	 * @return track quality
	 */
	public String getTrackQuality() {
		if (audioFile == null) {
			createAudioFile();
		}
		return audioFile.getAudioHeader().getSampleRate() + " Hz, " + audioFile.getAudioHeader().getBitRate() + " kbps";
	}
	
	public long getTrackBitrate() {
		if (audioFile == null) {
			createAudioFile();
		}
		return audioFile.getAudioHeader().getBitRateAsNumber();
	}

	/**
	 * Return file format as string like "mp3"
	 * @return file format
	 */
	public String getFileFormat() {
		if (audioFile == null) {
			createAudioFile();
		}
		return audioFile.getAudioHeader().getEncodingType();
	}
	
	/**
	 * Return formated time as string like mmm:ss
	 * @param length time in seconds
	 * @return time as formated string
	 */
	private String timeFormater(int length) {
		int m = length / 60;
		int s = length % 60;
		// may be we must use string formater here??? 
		String ss = String.valueOf(s);
		if (ss.length() == 1)
			ss = "0" + ss;
		return String.valueOf(m) + ":" + ss;
	}
	
	/**
	 * Return formated bytes as string like x B, x kB, x MB
	 * @param size bytes
	 * @return bytes as formated string
	 */
	private String byteFormater(long size) {
		float fsize = size;
		float result = fsize;
		
		DecimalFormat df = new DecimalFormat("###.##");
		
		if (result < 1024)
			return String.valueOf(result) + "b";
		result /= 1024;
		if (result < 1024)
			return df.format(result) + "kB";
		result /= 1024;
		if (result < 1024)
			return df.format(result) + "MB";
		
		return String.valueOf(size) + "b";
	}
	
	private void createAudioFile() {
		try {
			audioFile = AudioFileIO.read(file);
			tag = audioFile.getTag();
		} catch (CannotReadException e) {
			BaseLogger.error("FSFile reader", e);
		} catch (IOException e) {
			BaseLogger.error("FSFile reader", e);
		} catch (TagException e) {
			BaseLogger.error("FSFile reader", e);
		} catch (ReadOnlyFileException e) {
			BaseLogger.error("FSFile reader", e);
		} catch (InvalidAudioFrameException e) {
			BaseLogger.error("FSFile reader", e);
		}
	}

	private void createMP3File() throws FSException {
		if (!getFileFormat().equals("mp3")) {
			throw new FSException("Can't process file. It's not mp3 format");
		}
		
		try {
			mp3file = (MP3File) AudioFileIO.read(file);
		} catch (Exception e) {
			throw new FSException("FSFile convertion to mp3 exception", e);
		}
	}
	
	public boolean hasID3v1Tag() {
		if (mp3file == null) {
			try {
				createMP3File();
			} catch (FSException e) {
				e.printStackTrace();
			}
		}
		mp3v1Tag = mp3file.getID3v1Tag();
		return mp3file.hasID3v1Tag();
	}

	public String getV1Title() {
		return mp3v1Tag.getFirstTitle();
	}

	public String getV1Artist() {
		return mp3v1Tag.getFirst(FieldKey.ARTIST);
	}

	public String getV1Album() {
		return mp3v1Tag.getFirst(FieldKey.ALBUM);
	}

	public String getV1Genre() {
		return mp3v1Tag.getFirst(FieldKey.GENRE);
	}

	public String getV1Year() {
		return mp3v1Tag.getFirst(FieldKey.YEAR);
	}

	public String getV1TrackNo() {
		return mp3v1Tag.getFirst(FieldKey.TRACK);
	}

	public String getV1DiskNo() {
		return mp3v1Tag.getFirst(FieldKey.DISC_NO);
	}

	public boolean hasID3v2Tag() {
		if (mp3file == null) {
			try {
				createMP3File();
			} catch (FSException e) {
				e.printStackTrace();
			}
		}
		mp3v2Tag = mp3file.getID3v2TagAsv24();
		return mp3file.hasID3v2Tag();
	}

	public String getV2Title() {
		return mp3v2Tag.getFirst(ID3v24Frames.FRAME_ID_TITLE);
	}

	public String getV2Artist() {
		return mp3v2Tag.getFirst(ID3v24Frames.FRAME_ID_ARTIST);
	}

	public String getV2Album() {
		return mp3v2Tag.getFirst(ID3v24Frames.FRAME_ID_ALBUM);
	}

	public String getV2Genre() {
		return mp3v2Tag.getFirst(ID3v24Frames.FRAME_ID_GENRE);
	}

	public String getV2Year() {
		return mp3v2Tag.getFirst(ID3v24Frames.FRAME_ID_YEAR);
	}

	public String getV2TrackNo() {
		return mp3v2Tag.getFirst(ID3v24Frames.FRAME_ID_TRACK);
	}
}
